// * Fn.prototype 通过构造函数设置实例对象的原型。
// * F.prototype 的值要么是一个对象，要么就是 null；其他值无效。
// * "prototype" 属性仅当设置在一个构造函数上，并通过 new 调用时，才具有这种特殊的影响（指定实例对象的原型）。

let animal = {
	eats: true,
}

function Rabbit(name) {
	this.name = name
}

// * 这段代码是指：仅在当创建一个 new Rabbit 时，会把它实例对象的原型设置为 animal。
// * 如果在创建之后，F.prototype 属性有了变化（整个对象被替换）。那么通过 new F 创建的新对象也将随之拥有新的对象作为 [[Prototype]]，但已经存在的对象将保持旧有的值。
Rabbit.prototype = animal

// rabbit.__proto__ = animal
let rabbit = new Rabbit('兔八哥')

console.log(rabbit.eats) // true

// *******************************************************************************************************************

// * 默认的 Fn.prototype，构造器属性。

// * 每个函数都有一个默认的 prototype 属性，即使我们没有提供它。
// * 默认的 prototype 是一个只有属性 constructor 的对象，属性 constructor 指向函数自身。

// * 例子1：
function Fn() {} // 类似于这样 Fn.prototype = { constructor: Fn }
console.log(Fn.prototype.constructor === Fn) // true

// * 例子2：
function Fn2() {} // Fn2.prototype = { constructor: Fn2 }
let fn2 = new Fn2() // fn2.__proto__ = { constructor: Fn2 }
console.log(fn2.constructor === Fn2) // true
let newfn2 = new fn2.constructor()
console.log(newfn2.constructor === Fn2) // true

// * 例子3：函数的默认 prototype 属性的值，是可以被替换成一个新对象的，如果我们想要保留里面 constructor 属性，可以不完全替换或手动创建。
// (1)
function Func() {}
// * 我们只往默认的 prototype 中添加新属性，而不是覆盖整个对象，所以 constructor 保留下来了。
Func.prototype.name = '我是实例对象原型中的name属性'

// (2)
function Func2() {}
Func2.prototype = { name: '我是实例对象原型中的name属性', constructor: Func2 }
